﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

//HELLO KOLAN@!!!!!!
//privet test!!!!!
namespace SimpleMiner
{
	//testtstrte
	//testtstrte
    public partial class Form1 : Form
    {
        const int ELEM_SIZE = 30;//px

        const int MIN_COUNT = 99;
        const int PLANE_SIZE_X=30;
        const int PLANE_SIZE_Y=16;

        Color[] cNumbers = new Color[8];

        enum elem {none, mine}
        enum userelem { close, flag, mine, minefail, notmine, quest, mousedown, none, n1, n2, n3, n4, n5, n6, n7, n8 }

        elem[,] m_Plane = new elem[PLANE_SIZE_X, PLANE_SIZE_Y];
        userelem[,] m_UserPlane = new userelem[PLANE_SIZE_X, PLANE_SIZE_Y];
        int Mines = 0;

        bool LMousePressed = false;
        bool RMousePressed = false;

        bool isGameOverPreview = false;
        bool isGameOver = true;

        public Form1()
        {
            InitializeComponent();

            cNumbers[0] = Color.Blue;
            cNumbers[1] = Color.Green;
            cNumbers[2] = Color.Red;
            cNumbers[3] = Color.DarkBlue;
            cNumbers[4] = Color.DarkMagenta;
            cNumbers[5] = Color.Magenta;
            cNumbers[6] = Color.DeepPink;
            cNumbers[7] = Color.Black;

            for (int i=0; i<PLANE_SIZE_X; i++)
                for (int j = 0; j < PLANE_SIZE_Y; j++)
                {
                    m_Plane[i, j] = elem.none;
                    m_UserPlane[i, j] = userelem.close;
                }


            Width = ELEM_SIZE * PLANE_SIZE_X + 6;
            Height = ELEM_SIZE * PLANE_SIZE_Y + 24;

            SetCapture();
        }

        void StartGame(int startX, int startY)
        {
            Mines = 0;
            isGameOverPreview = false;
            isGameOver = false;
            SetCapture();
            do
            {
                int x, y;
                Random r = new Random();
                while (Mines < MIN_COUNT)
                {
                    x = r.Next(PLANE_SIZE_X);
                    y = r.Next(PLANE_SIZE_Y);
                    if (m_Plane[x, y] == elem.none)
                    {
                        m_Plane[x, y] = elem.mine;
                        Mines++;
                    }
                }

                if (getElemState(startX, startY) == userelem.none) break;
                else
                {
                    Mines = 0;
                    for (int i = 0; i < PLANE_SIZE_X; i++)
                        for (int j = 0; j < PLANE_SIZE_Y; j++)
                            m_Plane[i, j] = elem.none;
                }
            } while (true);

            for (int i = 0; i < PLANE_SIZE_X; i++)
                for (int j = 0; j < PLANE_SIZE_Y; j++)
                    m_UserPlane[i, j] = userelem.close;
            OpenElem(startX, startY);
        }

        void SetCapture()
        {
            Text = Mines.ToString() + " mines left";
			///TESTets 
			//dfsfsd
        }

        void Draw3DBorder(Graphics g, int i, int j)
        {
            Pen pGray = new Pen(Color.Gray);
            Pen pWhite = new Pen(Color.White);
            Pen pDGray = new Pen(Color.DarkGray);

            g.DrawLine(pWhite, ELEM_SIZE * i, ELEM_SIZE * j,
                                                   ELEM_SIZE * i + ELEM_SIZE - 1, ELEM_SIZE * j);
            g.DrawLine(pWhite, ELEM_SIZE * i, ELEM_SIZE * j + 1,
                               ELEM_SIZE * i + ELEM_SIZE - 2, ELEM_SIZE * j + 1);
            g.DrawLine(pWhite, ELEM_SIZE * i, ELEM_SIZE * j,
                               ELEM_SIZE * i, ELEM_SIZE * j + ELEM_SIZE - 2);
            g.DrawLine(pWhite, ELEM_SIZE * i + 1, ELEM_SIZE * j,
                               ELEM_SIZE * i + 1, ELEM_SIZE * j + ELEM_SIZE - 3);

            g.DrawLine(pDGray, ELEM_SIZE * i, ELEM_SIZE * j + ELEM_SIZE - 1,
                               ELEM_SIZE * i + ELEM_SIZE - 1, ELEM_SIZE * j + ELEM_SIZE - 1);
            g.DrawLine(pDGray, ELEM_SIZE * i + 1, ELEM_SIZE * j + ELEM_SIZE - 2,
                               ELEM_SIZE * i + ELEM_SIZE - 1, ELEM_SIZE * j + ELEM_SIZE - 2);
            g.DrawLine(pDGray, ELEM_SIZE * i + ELEM_SIZE - 1, ELEM_SIZE * j + ELEM_SIZE - 1,
                               ELEM_SIZE * i + ELEM_SIZE - 1, ELEM_SIZE * j + 1);
            g.DrawLine(pDGray, ELEM_SIZE * i + ELEM_SIZE - 2, ELEM_SIZE * j + ELEM_SIZE - 1,
                               ELEM_SIZE * i + ELEM_SIZE - 2, ELEM_SIZE * j + 2);
        }

        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;

            Pen pGray = new Pen(Color.Gray);
            Pen pWhite = new Pen(Color.White);
            Pen pDGray = new Pen(Color.DarkGray);
            Pen pBlackLine = new Pen(Color.Black, 3.0f);

            for (int i=0; i<PLANE_SIZE_X; i++)
                for (int j = 0; j < PLANE_SIZE_Y; j++)
                {
                    switch (m_UserPlane[i,j])
                    {
                        case userelem.close:
                            {
                                Draw3DBorder(g, i, j);
                                break;
                            }
                        case userelem.flag:
                                {
                                    Draw3DBorder(g, i, j);
                                    g.DrawImage(Properties.Resources.ImgMineFlag,
                                        new Point(i * ELEM_SIZE + ELEM_SIZE / 2 - Properties.Resources.ImgMineFlag.Width / 2 ,
                                                  j * ELEM_SIZE + ELEM_SIZE / 2 - Properties.Resources.ImgMineFlag.Height / 2));
                                    break;
                                }
                        case userelem.none:
                        case userelem.mousedown:
                                {
                                    g.DrawRectangle(pDGray, ELEM_SIZE * i, ELEM_SIZE * j, ELEM_SIZE, ELEM_SIZE);
                                    break;
                                }
                        case userelem.notmine:
                                {
                                    Draw3DBorder(g, i, j);
                                    g.DrawImage(Properties.Resources.ImgNotMine,
                                        new Point(i * ELEM_SIZE + ELEM_SIZE / 2 - Properties.Resources.ImgNotMine.Width / 2 - 2,
                                                  j * ELEM_SIZE + ELEM_SIZE / 2 - Properties.Resources.ImgNotMine.Height / 2 - 2));
                                    
                                    break;
                                }
                        case userelem.mine:
                                {
                                    Draw3DBorder(g, i, j);
                                    g.DrawImage(Properties.Resources.ImgMine,
                                        new Point(i * ELEM_SIZE + ELEM_SIZE / 2 - Properties.Resources.ImgMine.Width / 2 - 2,
                                                  j * ELEM_SIZE + ELEM_SIZE / 2 - Properties.Resources.ImgMine.Height / 2 - 2));

                                    break;
                                }
                        case userelem.minefail:
                                {
                                    g.FillRectangle(Brushes.DarkRed, ELEM_SIZE * i, ELEM_SIZE * j, ELEM_SIZE - 1, ELEM_SIZE - 1);
                                    Draw3DBorder(g, i, j);
                                    g.DrawImage(Properties.Resources.ImgMine,
                                        new Point(i * ELEM_SIZE + ELEM_SIZE / 2 - Properties.Resources.ImgMine.Width / 2 - 2,
                                                  j * ELEM_SIZE + ELEM_SIZE / 2 - Properties.Resources.ImgMine.Height / 2 - 2));
                                    
                                    break;
                                }
                        case userelem.quest:
                                {
                                    Draw3DBorder(g, i, j);
                                    String str = "?";
                                    g.DrawString(str, new Font("Arial", 15.0f), new SolidBrush(Color.Black),
                                                 ELEM_SIZE * i + 7, ELEM_SIZE * j + 5);
                                    break;
                                }
                        default:
                            {
                                g.DrawRectangle(pDGray, ELEM_SIZE * i, ELEM_SIZE * j, ELEM_SIZE, ELEM_SIZE);
                                String str = "" + (m_UserPlane[i, j] - userelem.n1 + 1);
                                g.DrawString(str, new Font("Arial", 15.0f), new SolidBrush(cNumbers[(m_UserPlane[i, j] - userelem.n1)]), 
                                             ELEM_SIZE * i + 7, ELEM_SIZE * j + 5);
                                break;
                            }
                    }
                }
        }

        private userelem getElemState(int x, int y)
        {
            if (m_Plane[x, y] == elem.mine) return userelem.minefail;

            int mine_count = 0;

            if ((x > 0) && (y > 0) && (m_Plane[x - 1, y - 1] == elem.mine))
                mine_count++;
            if ((y > 0) && (m_Plane[x, y - 1] == elem.mine))
                mine_count++;
            if ((x < PLANE_SIZE_X - 1) && (y > 0) && (m_Plane[x + 1, y - 1] == elem.mine))
                mine_count++;

            if ((x > 0) && (m_Plane[x - 1, y] == elem.mine))
                mine_count++;
            if ((x < PLANE_SIZE_X - 1) && (m_Plane[x + 1, y] == elem.mine))
                mine_count++;

            if ((x > 0) && (y < PLANE_SIZE_Y - 1) && (m_Plane[x - 1, y + 1] == elem.mine))
                mine_count++;
            if ((y < PLANE_SIZE_Y - 1) && (m_Plane[x, y + 1] == elem.mine))
                mine_count++;
            if ((x < PLANE_SIZE_X - 1) && (y < PLANE_SIZE_Y - 1) && (m_Plane[x + 1, y + 1] == elem.mine))
                mine_count++;
            return userelem.none + mine_count;
        }

        private byte getMineFlagsAround(int x, int y)
        {
            if (m_Plane[x, y] == elem.mine) return 0;

            byte mine_flags_count = 0;

            if ((x > 0) && (y > 0) && (m_UserPlane[x - 1, y - 1] == userelem.flag))
                mine_flags_count++;
            if ((y > 0) && (m_UserPlane[x, y - 1] == userelem.flag))
                mine_flags_count++;
            if ((x < PLANE_SIZE_X - 1) && (y > 0) && (m_UserPlane[x + 1, y - 1] == userelem.flag))
                mine_flags_count++;

            if ((x > 0) && (m_UserPlane[x - 1, y] == userelem.flag))
                mine_flags_count++;
            if ((x < PLANE_SIZE_X - 1) && (m_UserPlane[x + 1, y] == userelem.flag))
                mine_flags_count++;

            if ((x > 0) && (y < PLANE_SIZE_Y - 1) && (m_UserPlane[x - 1, y + 1] == userelem.flag))
                mine_flags_count++;
            if ((y < PLANE_SIZE_Y - 1) && (m_UserPlane[x, y + 1] == userelem.flag))
                mine_flags_count++;
            if ((x < PLANE_SIZE_X - 1) && (y < PLANE_SIZE_Y - 1) && (m_UserPlane[x + 1, y + 1] == userelem.flag))
                mine_flags_count++;
            return mine_flags_count;
        }

        void DrawEmptyFields(int x, int y)
        {
            m_UserPlane[x, y] = getElemState(x, y);
            if (m_UserPlane[x, y] == userelem.none) m_UserPlane[x, y] = userelem.mousedown;
            else return;
            //draw around
            if ((x > 0) && (y > 0) && (m_UserPlane[x - 1, y - 1] != userelem.mousedown))
                DrawEmptyFields(x - 1, y - 1);
            if ((y > 0) && (m_UserPlane[x, y - 1] != userelem.mousedown))
                DrawEmptyFields(x, y - 1);
            if ((x < PLANE_SIZE_X - 1) && (y > 0) && (m_UserPlane[x + 1, y - 1] != userelem.mousedown))
                DrawEmptyFields(x + 1, y - 1);

            if ((x > 0) && (m_UserPlane[x - 1, y] != userelem.mousedown))
                DrawEmptyFields(x - 1, y);
            if ((x < PLANE_SIZE_X - 1) && (m_UserPlane[x + 1, y] != userelem.mousedown))
                DrawEmptyFields(x + 1, y);

            if ((x > 0) && (y < PLANE_SIZE_Y - 1) && (m_UserPlane[x - 1, y + 1] != userelem.mousedown))
                DrawEmptyFields(x - 1, y + 1);
            if ((y < PLANE_SIZE_Y - 1) && (m_UserPlane[x, y + 1] != userelem.mousedown))
                DrawEmptyFields(x, y + 1);
            if ((x < PLANE_SIZE_X - 1) && (y < PLANE_SIZE_Y - 1) && (m_UserPlane[x + 1, y + 1] != userelem.mousedown))
                DrawEmptyFields(x + 1, y + 1);
        }

        private void GameOver(int x, int y)
        {
            Text += " GAME OVER!";
            isGameOverPreview = true;
            m_UserPlane[x, y] = userelem.minefail;
            for (int i = 0; i < PLANE_SIZE_X; i++)
                for (int j = 0; j < PLANE_SIZE_Y; j++)
                {
                    if ((m_UserPlane[i, j] == userelem.close) && m_Plane[i, j] == elem.mine)
                        m_UserPlane[i, j] = userelem.mine;
                    if ((m_UserPlane[i, j] == userelem.flag) && m_Plane[i, j] == elem.none)
                        m_UserPlane[i, j] = userelem.notmine;
                }

        }

        private void OpenElem(int x, int y)
        {
            if (m_UserPlane[x, y] == userelem.flag) return;
            m_UserPlane[x, y] = getElemState(x, y);
            if (m_Plane[x, y] == elem.mine)
            {
                GameOver(x, y);
            }
            if (m_UserPlane[x, y] == userelem.none)
            {
                DrawEmptyFields(x, y);
                for (int i = 0; i < PLANE_SIZE_X; i++)
                    for (int j = 0; j < PLANE_SIZE_Y; j++)
                        if (m_UserPlane[i, j] == userelem.mousedown)
                            m_UserPlane[i, j] = userelem.none;
            }
            Invalidate(false);
        }

        private void OpenElemsAround(int x, int y)
        {
            if (m_UserPlane[x, y] == userelem.none) return;
            if ((m_UserPlane[x, y] < userelem.n1) || (getMineFlagsAround(x, y) != (m_UserPlane[x, y] - userelem.none)))
            {
                if (m_UserPlane[x, y] == userelem.none) return;
                //if (m_UserPlane[x, y] == userelem.quest) m_UserPlane[x, y] = userelem.mousedown;

                if ((x > 0) && (y > 0) && (m_UserPlane[x - 1, y - 1] == userelem.close))
                    m_UserPlane[x - 1, y - 1] = userelem.mousedown;
                if ((y > 0) && (m_UserPlane[x, y - 1] == userelem.close))
                    m_UserPlane[x, y - 1] = userelem.mousedown;
                if ((x < PLANE_SIZE_X - 1) && (y > 0) && (m_UserPlane[x + 1, y - 1] == userelem.close))
                    m_UserPlane[x + 1, y - 1] = userelem.mousedown;

                if ((x > 0) && (m_UserPlane[x - 1, y] == userelem.close))
                    m_UserPlane[x - 1, y] = userelem.mousedown;
                if ((x < PLANE_SIZE_X - 1) && (m_UserPlane[x + 1, y] == userelem.close))
                    m_UserPlane[x + 1, y] = userelem.mousedown;

                if ((x > 0) && (y < PLANE_SIZE_Y - 1) && (m_UserPlane[x - 1, y + 1] == userelem.close))
                    m_UserPlane[x - 1, y + 1] = userelem.mousedown;
                if ((y < PLANE_SIZE_Y - 1) && (m_UserPlane[x, y + 1] == userelem.close))
                    m_UserPlane[x, y + 1] = userelem.mousedown;
                if ((x < PLANE_SIZE_X - 1) && (y < PLANE_SIZE_Y - 1) && (m_UserPlane[x + 1, y + 1] == userelem.close))
                    m_UserPlane[x + 1, y + 1] = userelem.mousedown;
                Invalidate(false);
                return;
            }

            if ((x > 0) && (y > 0) && ((m_UserPlane[x - 1, y - 1] != userelem.flag)))
                OpenElem(x - 1, y - 1);
            if ((y > 0) && (m_UserPlane[x, y - 1] != userelem.flag))
                OpenElem(x, y - 1);
            if ((x < PLANE_SIZE_X - 1) && (y > 0) && (m_UserPlane[x + 1, y - 1] != userelem.flag))
                OpenElem(x + 1, y - 1);

            if ((x > 0) && (m_UserPlane[x - 1, y] != userelem.flag))
                OpenElem(x - 1, y);
            if ((x < PLANE_SIZE_X - 1) && (m_UserPlane[x + 1, y] != userelem.flag))
                OpenElem(x + 1, y);

            if ((x > 0) && (y < PLANE_SIZE_Y - 1) && (m_UserPlane[x - 1, y + 1] != userelem.flag))
                OpenElem(x - 1, y + 1);
            if ((y < PLANE_SIZE_Y - 1) && (m_UserPlane[x, y + 1] != userelem.flag))
                OpenElem(x, y + 1);
            if ((x < PLANE_SIZE_X - 1) && (y < PLANE_SIZE_Y - 1) && (m_UserPlane[x + 1, y + 1] != userelem.flag))
                OpenElem(x + 1, y + 1);
        }

        private void Form1_MouseDown(object sender, MouseEventArgs e)
        {
            Point pt = new Point(e.X / ELEM_SIZE, e.Y / ELEM_SIZE);

            if (e.Button == MouseButtons.Left)
            {
                LMousePressed = true;
                if (m_UserPlane[pt.X, pt.Y] == userelem.close)
                {
                    m_UserPlane[pt.X, pt.Y] = userelem.mousedown;
                    Invalidate(false);
                }
            }
            if (e.Button == MouseButtons.Right)
            {
                RMousePressed = true;
                if (LMousePressed)
                {
                    OpenElemsAround(pt.X, pt.Y);
                }
                else
                {
                    if (m_UserPlane[pt.X, pt.Y] == userelem.flag)
                    {
                        m_UserPlane[pt.X, pt.Y] = userelem.quest;
                        Mines++;
                    }
                    else if (m_UserPlane[pt.X, pt.Y] == userelem.close)
                    {
                        Mines--;
                        m_UserPlane[pt.X, pt.Y] = userelem.flag;
                    }
                    else if (m_UserPlane[pt.X, pt.Y] == userelem.quest)
                        m_UserPlane[pt.X, pt.Y] = userelem.close;
                    SetCapture();
                    Invalidate(false);
                }
            }
            
        }

        private void Form1_MouseMove(object sender, MouseEventArgs e)
        {
            if (LMousePressed)
            {
                Point pt = new Point(e.X / ELEM_SIZE, e.Y / ELEM_SIZE);
                if ((pt.X > PLANE_SIZE_X - 1) || (pt.Y > PLANE_SIZE_Y - 1) ||
                    (pt.X < 0) || (pt.Y < 0)) return;
                
                if (!RMousePressed)
                    for (int i=0; i<PLANE_SIZE_X; i++)
                        for (int j=0; j<PLANE_SIZE_Y; j++)
                            if (m_UserPlane[i, j] == userelem.mousedown)
                                m_UserPlane[i, j] = userelem.close;
                if (m_UserPlane[pt.X, pt.Y] == userelem.close)
                {
                    m_UserPlane[pt.X, pt.Y] = userelem.mousedown;
                    Invalidate(false);
                }
            }
        }

        private void Form1_MouseUp(object sender, MouseEventArgs e)
        {

            Point pt = new Point(e.X / ELEM_SIZE, e.Y / ELEM_SIZE);

            if (e.Button == MouseButtons.Left)
            {
                LMousePressed = false;

                if (isGameOver)
                {
                    StartGame(pt.X, pt.Y);
                }
                if (isGameOverPreview)
                {
                    isGameOverPreview = false;
                    isGameOver = true;
                }

                if (!RMousePressed) OpenElem(pt.X, pt.Y);
            }
            if (e.Button == MouseButtons.Right)
            {
                RMousePressed = false;
                for (int i = 0; i < PLANE_SIZE_X; i++)
                    for (int j = 0; j < PLANE_SIZE_Y; j++)
                        if (m_UserPlane[i, j] == userelem.mousedown)
                            m_UserPlane[i, j] = userelem.close;
            }
            Invalidate(false);
        }
    }
}
